package com.gcsoftware.web.service;

import com.gcsoftware.gw.beans.*;
import com.gcsoftware.gw.xml.GwXmlUtil;
import com.gcsoftware.web.beans.T_GW_DSITEM;
import com.gcsoftware.web.beans.T_GW_INTERFS;
import com.gcsoftware.web.beans.T_GW_INTERF_PARAMS;
import com.gcsoftware.web.mapper.T_GW_APPSMAPPER;
import com.gcsoftware.web.mapper.T_GW_DSITEMMAPPER;
import com.gcsoftware.web.mapper.T_GW_INTERFMAPPER;
import com.gcsoftware.web.mapper.T_GW_ROLEMAPPER;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.*;

/**
 * Created by qs on 2018/4/10.
 */
@Service
public class FileUploadService {
    private Logger logger = LoggerFactory.getLogger(FileUploadService.class);

    @Autowired
    private T_GW_ROLEMAPPER roleMapper;

    @Autowired
    private T_GW_INTERFMAPPER interfMapper;

    @Autowired
    private T_GW_APPSMAPPER appMapper;

    @Autowired
    private T_GW_DSITEMMAPPER dsiItemMapper;

    @Value("${datasecurity.gateway.upload.path}")
    String gatewayUrl;

    private Map<String,List<T_GW_INTERF_PARAMS>> getInterfIparamsMap( String roleId) {
        List<T_GW_INTERF_PARAMS> iparamList = interfMapper.queryIparamsForRole(roleId);

        List<T_GW_INTERF_PARAMS> iprm4Interf = null;
        Map<String , T_GW_INTERF_PARAMS> iparamsMap = null;
        Map<String , Object> interfMap = null;

        Map<String,List<T_GW_INTERF_PARAMS>> resultMap = null;

        if (CollectionUtils.isNotEmpty(iparamList)) {
            iparamsMap = new HashMap<>();
            interfMap = new HashMap<>();
            T_GW_INTERF_PARAMS prm = null;
            for (T_GW_INTERF_PARAMS iparam : iparamList) {
                iparamsMap = (Map<String, T_GW_INTERF_PARAMS>) interfMap.get(iparam.getC_INTERF_ID());
                if (null == iparamsMap) iparamsMap = new HashMap<>();
                prm = (T_GW_INTERF_PARAMS) iparamsMap.get(iparam.getC_IPARAMS_ID());
                if (null == prm) {
                    iparamsMap.put(iparam.getC_IPARAMS_ID(),iparam);
                } else {
                    //不同的安全项选择了同一个接口进行保护时，保护替换信息选择第一个不为空的值
                    if (StringUtils.isBlank(prm.getC_IPARAMS_SENS()) && StringUtils.isNotBlank(iparam.getC_IPARAMS_SENS())) {
                        iparamsMap.put(iparam.getC_IPARAMS_ID(),iparam);
                    }
                }
                interfMap.put(iparam.getC_INTERF_ID(), iparamsMap);
            }

            for (Map.Entry<String , Object> entry : interfMap.entrySet()) {
                if (null == resultMap) {
                    resultMap = new HashMap<>();
                }
                iparamsMap = (Map<String, T_GW_INTERF_PARAMS>) entry.getValue();
                iprm4Interf = new ArrayList<>();
                for (Map.Entry<String,T_GW_INTERF_PARAMS> prmEntry : iparamsMap.entrySet()) {
                    iprm4Interf.add(prmEntry.getValue());
                }
                resultMap.put(entry.getKey(),iprm4Interf);
            }
        }
        return resultMap;
    }

    Map<String, List<GwAccessItem>> itemMap = null;
    private List<GwAccessItems> getAccessItemsByMethod(List<T_GW_INTERF_PARAMS> iparams, boolean ifUnify) {
        itemMap = new HashMap<>();
        List<GwAccessItems> itemsList = null;
        List<GwAccessItem> itemList = null;
        GwAccessItems items = null;
        GwAccessItem item = null;
        for (T_GW_INTERF_PARAMS param : iparams) {
            item = new GwAccessItem();
            item.setGwIsabeld(param.getIsAbled());
            item.setGwSensValue(param.getC_IPARAMS_SENS());
            item.setGwFieldtype(param.getC_IPARAMS_DATATYPE());
            item.setGwFieldname(param.getC_IPARAMS_NAME());

            if (ifUnify) {
                itemList = itemMap.get(param.getC_IPARAMS_SERVICE());
                if ( null == itemList) itemList = new ArrayList<>();
                itemList.add(item);
                itemMap.put(param.getC_IPARAMS_SERVICE(), itemList);
            } else {
                if ( null == itemList) itemList = new ArrayList<>();
                itemList.add(item);
            }
        }
        if (ifUnify) {
            if (null != itemMap && itemMap.size() > 0) {
                for (Map.Entry<String, List<GwAccessItem>> entry : itemMap.entrySet()) {
                    items = new GwAccessItems();
                    items.setGwServiceId(entry.getKey());
                    items.getGwAccessItem().addAll(entry.getValue());

                    if (null == itemsList) {
                        itemsList = new ArrayList<>();
                    }
                    itemsList.add(items);
                }
            }

        } else {
            if (CollectionUtils.isNotEmpty(itemList)) {
                items = new GwAccessItems();
                items.getGwAccessItem().addAll(itemList);

                if (null == itemsList) {
                    itemsList = new ArrayList<>();
                }
                itemsList.add(items);
            }
        }
        return itemsList;
    }

    private GwAccessRole getGatewayAccessRole(String roleId) {
        /*
        从上往下按层级关系定义好实体类，如果有不明白之处，可以查看data-security-common包resource下的xsd文件
         */
        /**
         * 每个GwAccessRole对象包含一个RoleId下的所有接口和参数，以及参数是否被保护
         */
        GwAccessRole gwAccessRole = null;

        GwAccessInterfs accessInterfs = null;
        //当前RoleId允许访问的所有接口的发布地址，实际存放T_GW_INTERF表中的c_INTERF_ENDPOINT字段
        List<String> gwAccessInterfs = null;

        //根据发布地址存放应用ip，是否使用唯一接口，使用唯一接口时的关键判别字段，和接口方法及返回参数列表
        List<GwAccessRoleUris> roleUrisList = null;
        GwAccessRoleUris roleUris = null;

        Map<String, GwAccessRoleUris> accessUriMap = null;
        Set<String> accessUriSet = new HashSet<>();

        //接口对应的app的Ip地址
        List<String> appIps = null;

        Map<String , List<GwAccessRoleUri>> roleUriMap = null;

        //根据不同的接口方法名返回不同的参数列表
        List<GwAccessRoleUri> roleUriList = null;
        GwAccessRoleUri roleUri = null;

        //如果访问的接口为统一入口，可能会不同的服务返回不同的参数，则会返回一组GwAccessItem
        List<GwAccessItems> itemsList = null;
        GwAccessItem item = null;

        List<T_GW_INTERF_PARAMS> iparams = null;

        Map<String, List<T_GW_INTERF_PARAMS>> iparamsMap = getInterfIparamsMap(roleId);
        if (null == iparamsMap || iparamsMap.size() == 0) {
            logger.error("There is no interface parameters for role[{}]",roleId);
            return null;
        }

        logger.debug("To query all interfaces for role which can access ");
        List<T_GW_INTERFS> interfList = roleMapper.queryAccessInterfListForRole(roleId);
        if (CollectionUtils.isNotEmpty(interfList)) {
            roleUriMap = new HashMap<>();
            for (T_GW_INTERFS interf: interfList) {
                if (null == gwAccessInterfs) gwAccessInterfs = new ArrayList<>();
                gwAccessInterfs.add(interf.getC_INTERF_ENDPOINT());
                iparams = iparamsMap.get(interf.getC_INTERF_ID());
                itemsList = getAccessItemsByMethod(iparams, "1".equals(interf.getC_INTERF_UNIFY()));
                if (CollectionUtils.isNotEmpty(itemsList)) {
                    roleUri = new GwAccessRoleUri();
                    roleUri.setUri(interf.getC_INTERF_METHOD_NAME());
                    roleUri.getGwAccessItems().addAll(itemsList);

                    roleUriList = roleUriMap.get(interf.getC_INTERF_ENDPOINT());
                    if (null == roleUriList) roleUriList = new ArrayList<>();

                    roleUriList.add(roleUri);

                    roleUriMap.put(interf.getC_INTERF_ENDPOINT(),roleUriList);

                    if (accessUriSet.add(interf.getC_INTERF_ENDPOINT())) {
                        //roleUris = accessUriMap.get(interf.getC_INTERF_ENDPOINT());
                        roleUris = new GwAccessRoleUris();
                        roleUris.setGwAccessInterf(interf.getC_INTERF_ENDPOINT());
                        roleUris.setGwAccessUnify(interf.getC_INTERF_UNIFY());
                        roleUris.setGwAccessService(interf.getC_INTERF_SERVICE());

                        if (null == accessUriMap ) accessUriMap = new HashMap<>();
                        accessUriMap.put(interf.getC_INTERF_ENDPOINT(),roleUris);
                    }
                }
            }

            if (null != accessUriMap && accessUriMap.size() > 0) {
                roleUrisList = new ArrayList<>();
                for (Map.Entry entry : accessUriMap.entrySet()) {
                    roleUris = (GwAccessRoleUris) entry.getValue();
                    roleUris.getGwAccessRoleUri().addAll(roleUriMap.get(entry.getKey()));
                    roleUrisList.add(roleUris);
                }
                if (CollectionUtils.isNotEmpty(roleUrisList) ) {
                    gwAccessRole = new GwAccessRole();
                    gwAccessRole.setRoleId(roleId);
                    gwAccessRole.getGwAccessRoleUris().addAll(roleUrisList);

                    List<T_GW_DSITEM> dsItemsForRole = dsiItemMapper.itemListForRole(roleId);
                    if (CollectionUtils.isNotEmpty(dsItemsForRole)) {
                        String sensIds = "";
                        String sensNames ="";
                        for (T_GW_DSITEM dsItem : dsItemsForRole) {
                            sensIds += dsItem.getC_DS_ITEM_ID() + ",";
                            sensNames += dsItem.getC_DS_ITEM_NAME() + ",";
                        }
                        if (StringUtils.isNotBlank(sensIds)) {
                            sensIds = sensIds.substring(0 , sensIds.lastIndexOf(","));
                            sensNames = sensNames.substring(0 , sensNames.lastIndexOf(","));
                            gwAccessRole.setGwAccessSensIds(sensIds);
                            gwAccessRole.setGwAccessSensNames(sensNames);
                        }
                    }

                    accessInterfs = new GwAccessInterfs();
                    accessInterfs.getGwAccessInterf().addAll(gwAccessInterfs);
                    gwAccessRole.setGwAccessInterfs(accessInterfs);
                } else {
                    return null;
                }
            }
        }
        return gwAccessRole;
    }

    public String getXmlByRoleId(String roleId) {
        logger.debug("get xml by role id {}" , roleId);

        GwAccessRole accessRole = getGatewayAccessRole(roleId);
        if (null != accessRole) {
            return GwXmlUtil.createXML(GwAccessRole.class,accessRole);
        }
        return null;
    }

    /**
     *
     * @param roleId
     * @return
     */
    public String fileUpload(String roleId) {
        String xml = getXmlByRoleId(roleId);
        System.out.println(xml);
        if (StringUtils.isNotBlank(xml)) {
            return post(xml);
        }
        return "";
    }

    public String post(String xml) {
        //创建httpclient工具对象
        HttpClient client = new HttpClient();
        //创建post请求方法
        PostMethod myPost = new PostMethod(gatewayUrl);
        //设置请求超时时间
        client.setConnectionTimeout(300*1000);
        String responseString = null;
        InputStream body= null;
        BufferedInputStream bis = null;
        ByteArrayOutputStream bos = null;
        try{
            //设置请求头部类型
            myPost.setRequestHeader("Content-Type","text/xml");
            myPost.setRequestHeader("Via","DsSolutionUpload");
            myPost.setRequestHeader("charset","utf-8");

            //设置请求体，即xml文本内容，注：这里写了两种方式，一种是直接获取xml内容字符串，一种是读取xml文件以流的形式
            //          myPost.setRequestBody(xmlString);

            body=new ByteArrayInputStream(xml.getBytes());
//            myPost.setRequestBody(body);
            myPost.setRequestEntity(new StringRequestEntity(xml,"text/xml","utf-8"));
            logger.info("Execute to DataSecurityGateway.");
            int statusCode = client.executeMethod(myPost);
            if(statusCode == HttpStatus.SC_OK){
                bis = new BufferedInputStream(myPost.getResponseBodyAsStream());
                byte[] bytes = new byte[1024];
                bos = new ByteArrayOutputStream();
                int count = 0;
                while((count = bis.read(bytes))!= -1){
                    bos.write(bytes, 0, count);
                }
                byte[] strByte = bos.toByteArray();
                responseString = new String(strByte,0,strByte.length,"utf-8");

            } else {
                logger.warn("WARNING!Post xml to DataSecurityGateway returns a statusCode {}" , statusCode);
            }
        }catch (Exception e) {
            logger.error("Post xml to DataSecurityGateway failed." , e);
        } finally {

            try {
                if (null != bos) {
                    bos.close();
                }
                if (null != bis) {
                    bis.close();
                }
                if (null != body) {
                    body.close();
                }
            } catch (IOException e) {
                logger.error("Close failed." , e);
            }
            myPost.releaseConnection();
        }

        return responseString;
    }
}
